package com.ppp.poi.utils;

/**
 * 1、WGS-84坐标系：地心坐标系，GPS原始坐标体系
 *
 * 在中国，任何一个地图产品都不允许使用GPS坐标，据说是为了保密。
 *
 * 2、GCJ-02 坐标系：国测局坐标，火星坐标系
 *
 * 1）国测局02年发布的坐标体系，它是一种对经纬度数据的加密算法，即加入随机的偏差。
 *
 * 2）互联网地图在国内必须至少使用GCJ-02进行首次加密，不允许直接使用WGS-84坐标下的地理数据，同时任何坐标系均不可转换为WGS-84坐标。
 *
 * 3）是国内最广泛使用的坐标体系，高德、腾讯、Google中国地图都使用它。
 *
 * 3、CGCS2000坐标系：国家大地坐标系
 *
 * 该坐标系是通过中国GPS 连续运行基准站、 空间大地控制网以及天文大地网与空间地网联合平差建立的地心大地坐标系统。
 *
 * 4、BD-09坐标系
 *
 * 百度中国地图所采用的坐标系，由GCJ-02进行进一步的偏移算法得到。
 *
 * 5、搜狗坐标系
 *
 * 搜狗地图所采用的坐标系，由GCJ-02进行进一步的偏移算法得到。
 *
 * 6、图吧坐标系
 *
 * 图吧地图所采用的坐标系，由GCJ-02进行进一步的偏移算法得到。
 *
 *
 * 各地图API坐标系统比较与转换; 
 *
 * WGS84坐标系：即地球坐标系，国际上通用的坐标系。设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系, 
 *
 * 谷歌地图采用的是WGS84地理坐标系（中国范围除外）; 
 *
 * GCJ02坐标系：即火星坐标系，是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。 
 *
 * 谷歌中国地图和搜搜中国地图采用的是GCJ02地理坐标系; BD09坐标系：即百度坐标系，GCJ02坐标系经加密后的坐标系; 
 *
 * 搜狗坐标系、图吧坐标系等，估计也是在GCJ02基础上加密而成的。
 */
public class GpsUtils {

  private static double x_pi = 3.14159265358979324 * 3000.0 / 180.0;
  // π
  private static double pi = 3.1415926535897932384626;
  // 长半轴
  private static double a = 6378245.0;
  // 扁率
  private static double ee = 0.00669342162296594323;

  public static boolean out_of_china(double lon, double lat) {
    if (lon < 72.004 || lon > 137.8347) {
      return true;
    } else if (lat < 0.8293 || lat > 55.8271) {
      return true;
    }
    return false;
  }

  public static double transformlat(double lon, double lat) {
    double ret = -100.0 + 2.0 * lon + 3.0 * lat + 0.2 * lat * lat + 0.1 * lon * lat + 0.2 * Math.sqrt(Math.abs(lon));
    ret += (20.0 * Math.sin(6.0 * lon * pi) + 20.0 * Math.sin(2.0 * lon * pi)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(lat * pi) + 40.0 * Math.sin(lat / 3.0 * pi)) * 2.0 / 3.0;
    ret += (160.0 * Math.sin(lat / 12.0 * pi) + 320 * Math.sin(lat * pi / 30.0)) * 2.0 / 3.0;
    return ret;
  }

  public static double transformlng(double lon, double lat) {
    double ret = 300.0 + lon + 2.0 * lat + 0.1 * lon * lon + 0.1 * lon * lat + 0.1 * Math.sqrt(Math.abs(lon));
    ret += (20.0 * Math.sin(6.0 * lon * pi) + 20.0 * Math.sin(2.0 * lon * pi)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(lon * pi) + 40.0 * Math.sin(lon / 3.0 * pi)) * 2.0 / 3.0;
    ret += (150.0 * Math.sin(lon / 12.0 * pi) + 300.0 * Math.sin(lon / 30.0 * pi)) * 2.0 / 3.0;
    return ret;
  }

  /**
   * WGS84转GCJ02(火星坐标系)
   *
   * @param wgs_lon WGS84坐标系的经度
   * @param wgs_lat WGS84坐标系的纬度
   * @return 火星坐标数组
   */
  public static double[] wgs84togcj02(double wgs_lon, double wgs_lat) {
    if (out_of_china(wgs_lon, wgs_lat)) {
      return new double[]{wgs_lon, wgs_lat};
    }
    double dlat = transformlat(wgs_lon - 105.0, wgs_lat - 35.0);
    double dlng = transformlng(wgs_lon - 105.0, wgs_lat - 35.0);
    double radlat = wgs_lat / 180.0 * pi;
    double magic = Math.sin(radlat);
    magic = 1 - ee * magic * magic;
    double sqrtmagic = Math.sqrt(magic);
    dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi);
    dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * pi);
    double mglat = wgs_lat + dlat;
    double mglng = wgs_lon + dlng;
    return new double[]{mglng, mglat};
  }

  /**
   * GCJ02(火星坐标系)转GPS84
   *
   * @param gcj_lon 火星坐标系的经度
   * @param gcj_lat 火星坐标系纬度
   * @return WGS84坐标数组
   */
  public static double[] gcj02towgs84(double gcj_lon, double gcj_lat) {
    if (out_of_china(gcj_lon, gcj_lat)) {
      return new double[]{gcj_lon, gcj_lat};
    }
    double dlat = transformlat(gcj_lon - 105.0, gcj_lat - 35.0);
    double dlng = transformlng(gcj_lon - 105.0, gcj_lat - 35.0);
    double radlat = gcj_lat / 180.0 * pi;
    double magic = Math.sin(radlat);
    magic = 1 - ee * magic * magic;
    double sqrtmagic = Math.sqrt(magic);
    dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi);
    dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * pi);
    double mglat = gcj_lat + dlat;
    double mglng = gcj_lon + dlng;
    return new double[]{gcj_lon * 2 - mglng, gcj_lat * 2 - mglat};
  }


  /**
   * 火星坐标系(GCJ-02)转百度坐标系(BD-09)
   *
   * 谷歌、高德——>百度
   *
   * @param gcj_lon 火星坐标经度
   * @param gcj_lat 火星坐标纬度
   * @return 百度坐标数组
   */
  public static double[] gcj02tobd09(double gcj_lon, double gcj_lat) {
    double z = Math.sqrt(gcj_lon * gcj_lon + gcj_lat * gcj_lat) + 0.00002 * Math.sin(gcj_lat * x_pi);
    double theta = Math.atan2(gcj_lat, gcj_lon) + 0.000003 * Math.cos(gcj_lon * x_pi);
    double bd_lng = z * Math.cos(theta) + 0.0065;
    double bd_lat = z * Math.sin(theta) + 0.006;
    return new double[]{bd_lng, bd_lat};
  }

  /**
   * 百度坐标系(BD-09)转火星坐标系(GCJ-02)
   *
   * 百度——>谷歌、高德
   *
   * @param bd_lon 百度坐标纬度
   * @param bd_lat 百度坐标经度
   * @return 火星坐标数组
   */
  public static double[] bd09togcj02(double bd_lon, double bd_lat) {
    double x = bd_lon - 0.0065;
    double y = bd_lat - 0.006;
    double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
    double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
    double gg_lng = z * Math.cos(theta);
    double gg_lat = z * Math.sin(theta);
    return new double[]{gg_lng, gg_lat};
  }

  /**
   * WGS坐标转百度坐标系(BD-09)
   *
   * @param wgs_lng WGS84坐标系的经度
   * @param wgs_lat WGS84坐标系的纬度
   * @return 百度坐标数组
   */
  public static double[] wgs84tobd09(double wgs_lng, double wgs_lat) {
    double[] gcj = wgs84togcj02(wgs_lng, wgs_lat);
    double[] bd09 = gcj02tobd09(gcj[0], gcj[1]);
    return bd09;
  }

  /**
   * 百度坐标系(BD-09)转WGS坐标
   *
   * @param bd_lng 百度坐标纬度
   * @param bd_lat 百度坐标经度
   * @return WGS84坐标数组
   */
  public static double[] bd09towgs84(double bd_lng, double bd_lat) {
    double[] gcj = bd09togcj02(bd_lng, bd_lat);
    double[] wgs84 = gcj02towgs84(gcj[0], gcj[1]);
    return wgs84;
  }
}